<template>
  <div class="comp-data-table">
    <simple-virtual-table
      v-if="tableColumns && tableColumns.length > 0"
      ref="virtualTable"
      key-field="_record_id_"
      column-key="name"
      :data-sources="tableData"
      :data-column="tableColumns"
      :height="height"
      @table-body-scroll="onTableScroll"
    >
      <template #header="{column}">
        <span class="data-cell">{{ column.name }}</span>
      </template>

      <template #cell="{column, row, index:$index}">
        <div style="height: 100%;">
          <span
            :index="$index"
            :class="{
              'data-cell': true,
            }"
          >
            <!-- 这一层用于关键字高亮 -->
            <!-- <span
              class="cell-content"
              :class="{
                null: [undefined, null, ''].includes(row[column.name]),
              }"
              v-html="
                [undefined, null, ''].includes(row[column.name])
                  ? '-'
                  : selectionColumn !== column.name
                  ? row[column.name]
                  : getCellContent(
                      { column, row, $index, active },
                      column,
                      vrCurrenSetMode
                    )
              "
            >
            </span> -->
            <!-- 这一层用于触发刷选,请确保内容最后包含一个空格 -->
            <span class="cell-hilight" :title="row[column.name]"
              >{{ row[column.name] }}
            </span>
          </span>
        </div>
      </template>
    </simple-virtual-table>

    <!-- <u-table
      ref="uTable"
      size="mini"
      :select-tr-class="'select-tr'"
      :data="tableData"
      :height="height"
      :row-height="rowHeight"
      :data-changes-scroll-top="false"
      use-virtual
      border
      @cell-click="onCellClick"
      @table-body-scroll="onTableScroll"
      @header-click="onTableHeaderClick"
      @selection-change="handleSelectionChange">
      <u-table-column
        key="xuhao"
        :resizable="false"
        :lebel="'序号'"
        :prop="'$$$序号$$$'"
        :width="70"
        :fixed="true"
      >
      <span slot="header">序号</span>
      <span
        slot-scope="{$index}"
        class="data-cell index"
        :index="$index">
        <span class="data-index">
          {{$index + 1}}
        </span>
      </span>
      </u-table-column>
      <u-table-column
        v-for="item in tableColumns"
        :key="item.name"
        :class-name="checkIsSelect(item)? 'is-select-column' : ''"
        :resizable="item.resizable"
        :show-overflow-tooltip="false"
        :prop="item.name"
        :label="item.name"
        :fixed="item.fixed"
        >
        <span
        slot-scope="scope"
        class="data-cell"
        :index="scope.$index"
        :class="{
          'is-select-cell': checkIsSelectCell(scope) && !vrCurrenSetMode,
          'is-set-select-cell': vrCurrenSetMode
            && vrCurrenSetMode.selectionType === 'cells'
            && vrCurrenSetMode.column === item.name
            && vrCurrenSetMode.conditionTrigger(scope, GraphViewStore, item),
          'is-set-select-row': vrCurrenSetMode
            && vrCurrenSetMode.selectionType === 'rows'
            && vrCurrenSetMode.conditionTrigger(scope, GraphViewStore, item)
        }"> -->
    <!-- 这一层用于关键字高亮 -->
    <!-- <span
            class="cell-content"
            :class="{ null: [undefined, null, ''].includes(scope.row[item.name]) }"
            v-html=" getCellContent(scope, item, vrCurrenSetMode)">
          </span> -->
    <!-- 这一层用于触发刷选 -->
    <!-- <span
            class="cell-hilight"
            @mouseup="onCellTextMouseup($event, scope, item)">
            <a-tooltip placement="top">
              <span slot="title">{{scope.row[item.name]}}</span>{{scope.row[item.name]}}
            </a-tooltip>
          </span>
        </span>
      </u-table-column>
    </u-table> -->
  </div>
</template>

<script lang="ts">
import { Vue, Component, Watch } from 'vue-property-decorator'
import GraphViewStore, {
  CellInfo,
  IColumn,
  SelectionInfo,
} from '@/store/modules/graphview'
import SelectionType from '@/util/selection-type'
// @ts-ignore
// import { UTable, UTableColumn } from 'umy-table'
import SimpleVirtualTable from '@/components/simple-virtual-table/Table.vue'
import { apiGetTableData } from '@/api/data-clean'
import 'umy-table/lib/theme-chalk/index.css'
import { tcolumnQueryDetail } from '@/api/visualization'
import { isEqual } from 'lodash'
import VROptionSetModeInteface from '@/util/vr-option-set-mode-interface'

@Component({
  components: {
    SimpleVirtualTable,
  },
})
export default class GraphTable extends Vue {
  private rowHeight = 24
  private isLoading = false
  private totalPages: number = 0
  private multipleSelection: Array<any> = []
  private timeMouseDown: number = 0
  private timeMouseUp: number = 0

  private closeGraphModal: boolean = true

  private painationParams = {
    curPage: 1,
    name: '_record_id_', // 如果没有字段，那就固定传 _record_id_
    pageSize: 50,
    filter: [],
  }

  private get isMac() {
    const { userAgent } = window.navigator
    return userAgent.includes('Mac OS X')
  }

  private isCtrlSelect(event: MouseEvent) {
    if (this.isMac) {
      return event.metaKey
    }
    return event.ctrlKey
  }

  /**
   * 是否为刷选模式
   */
  public get IsSelectMode() {
    return GraphViewStore.tableSelectionType === SelectionType.selection
  }

  public get selectionText() {
    return GraphViewStore.tableSelectionInfo
      ? GraphViewStore.tableSelectionInfo.selection
      : ''
  }

  public get seletionRowIndex() {
    return GraphViewStore.tableSelectionInfo
      ? GraphViewStore.tableSelectionInfo.rowIndex
      : null
  }

  public get height() {
    const minHeight = 30
    return GraphViewStore.tableHeight < minHeight
      ? minHeight
      : GraphViewStore.tableHeight // GraphViewStore.tableHeight? GraphViewStore.tableHeight :  this.boxHeight
  }

  public get tableData() {
    return GraphViewStore.tableData
  }

  public get tableColumns() {
    return GraphViewStore.tableColumns
  }

  public get selectNode() {
    return GraphViewStore.selectNode
  }

  public get columnFilters() {
    return GraphViewStore.columnFilters
  }

  private get currentHistory() {
    return GraphViewStore.currentHistory
  }

  private get executionCompletionTime() {
    // pipeline节点执行后的更新时间
    return GraphViewStore.executionCompletionTime
  }
  private get selectColumns() {
    return GraphViewStore.tableSelectColumns
  }

  private get selectRowNumber() {
    return GraphViewStore.tableSelectRowNumbers
  }

  private get selectRowData() {
    return GraphViewStore.tableSelectRowDatas
  }

  private get executionCompletionType(): boolean {
    return GraphViewStore.executionCompletionType
  }

  private get vrCurrenSetMode() {
    return GraphViewStore.vrCurrenSetMode
  }

  private get GraphViewStore() {
    return GraphViewStore
  }

  @Watch('executionCompletionTime', { immediate: true })
  private onPipelineExecuteComplete(newValue: number, oldValue: number) {
    // pipeline节点执行完成后需要更新数据
    if (newValue !== oldValue && this.selectNode && this.selectNode.data) {
      const selectNode = GraphViewStore.pipelineNodes.filter(
        (node) => node.id === this.selectNode.id
      )[0] // 重新获取selectNode数据
      const { isSample } = selectNode.data // 获取当前节点是否采样阶段
      console.log(
        'onPipelineExecuteComplete',
        this.executionCompletionType,
        isSample
      )
      if (!this.executionCompletionType) {
        // 采样阶段执行完成
        // this.getTableDataByNode('refresh') // 采样完刷新数据
        if (isSample && ['CREATE', 'RUNNING'].includes(isSample)) {
          this.$message.info('当前为采样数据，全量任务后台运行中，请稍候', 4)
        }
        GraphViewStore.setSelectNode(selectNode)
      } else if (isSample) {
        // 全量任务完成
        this.$message.info('全量任务运行完成', 4)
        GraphViewStore.setSelectNode(selectNode) // 当前选中节点有全量任务时再更新
      }
    }
  }

  @Watch('selectRowData', { immediate: true, deep: true })
  private onSelectRowDataChange(newValue: Array<any>) {
    this.clearTableSlection()
    this.clearTableSelectCells()
    this.$nextTick(() => {
      this.toggleSelectionChange(newValue, true)
    })
  }

  mounted() {
    GraphViewStore.setTableSelectiontype(SelectionType.none)
    this.clearTableSelectCells()
    this.clearTableSlection()
    this.clearTableColumns()
    this.clearSelections()
    const win = window as any
    const that = this
    const keyUp = function (event: any) {
      if (event.code === 'Escape') {
        if (that.closeGraphModal) {
          that.$emit('close-modal')
        }
        that.clearTableSelectCells()
        that.clearTableSlection() //
        that.clearTableColumns()
        that.clearSelections()
        that.closeGraphModal = true
      }
    }

    const mouseDown = function () {
      that.timeMouseDown = new Date().valueOf()
    }
    const mouseUp = function () {
      that.timeMouseUp = new Date().valueOf()
    }

    win.document.addEventListener('mousedown', mouseDown)
    this.$once('hook:beforeDestroy', () => {
      win.document.removeEventListener('mousedown', mouseDown)
    })

    win.document.addEventListener('mouseup', mouseUp)
    this.$once('hook:beforeDestroy', () => {
      win.document.removeEventListener('mouseup', mouseUp)
    })

    win.document.addEventListener('keyup', keyUp)

    this.$once('hook:beforeDestroy', () => {
      win.document.removeEventListener('keyup', keyUp)
    })
  }
  /**
   * 清空所有选中状态
   */
  public clearAllSelect() {
    GraphViewStore.setTableSelectiontype(SelectionType.none)
    this.clearTableSelectCells()
    this.clearTableSlection()
    this.clearTableColumns()
    this.clearSelections()
  }
  /**
   * 获取渲染字段内容
   */
  getCellContent(
    scope: any,
    item: any,
    vrCurrenSetMode: VROptionSetModeInteface | null
  ) {
    // 推荐面板点击确定后的效果
    if (vrCurrenSetMode && vrCurrenSetMode.selectionType === 'selection') {
      return vrCurrenSetMode.conditionTrigger(scope, this.GraphViewStore, item)
    }
    let text = [undefined, null, ''].includes(scope.row[item.name])
      ? ''
      : (scope.row[item.name] as string)
    const selectionInfo = GraphViewStore.tableSelectionInfo
    // 转义 这里暂时做不了前端转义，转义后刷选的内容无法通过接口获取指定的值了
    // text = htmlEncode(text)
    const isMatch =
      scope.$index === this.seletionRowIndex ||
      (GraphViewStore.tableSelectionInfo?.rowIndexArray || []).includes(
        scope.$index
      )
    if (
      selectionInfo &&
      this.IsSelectMode &&
      isMatch &&
      this.selectionText !== '' &&
      text !== '' &&
      GraphViewStore.tableSelectionInfo?.columnName === item.name
    ) {
      // 这里不用replace是因为有可能刷选单词前面有相同字符串
      if (selectionInfo.isMutiple && selectionInfo.mutipleSelectionInfo) {
        // 从缓存里拿到刷选信息
        const setInfo = selectionInfo.mutipleSelectionInfo[
          `${scope.row._record_id_}_${scope.$index}`
        ] as SelectionInfo
        if (setInfo) {
          text = `${
            setInfo.startIndex > 0 ? text.slice(0, setInfo.startIndex) : ''
          }<span class="select-word">${setInfo.selection}</span>${text.slice(
            setInfo.endIndex,
            text.length
          )}`
        }
      } else {
        text = `${
          selectionInfo.startIndex > 0
            ? text.slice(0, selectionInfo.startIndex)
            : ''
        }<span class="select-word">${this.selectionText}</span>${text.slice(
          selectionInfo.endIndex,
          this.selectionText.length
        )}`
      }
    } else if (text === '') {
      text = '-'
    }
    return text
  }

  clearTableSelectCells() {
    GraphViewStore.setTableSelectCells([])
  }

  clearTableSlection() {
    this.multipleSelection = []
    const table = this.$refs.uTable as any
    if (table) {
      table.clearSelection()
    }
  }

  clearWindowSelection() {
    const document = (window as any).document as any
    if (window.getSelection) {
      // 获取选中
      const selection = window.getSelection()
      // 清除选中
      if (selection) {
        selection.removeAllRanges()
      }
    } else if (document.selection && document.selection.empty) {
      // 兼容 IE8 以下，但 IE9+ 以上同样可用
      document.selection.empty()
      // 或使用 clear() 方法
      // document.selection.clear();
    }
  }

  clearSelections() {
    this.clearWindowSelection()
    GraphViewStore.setTableSelectionInfo(null)
  }

  clearTableColumns() {
    GraphViewStore.setTableSelectColumns([])
    GraphViewStore.setSelectedColumns([])
  }

  /**
   * 当选择的节点变化时，重新触发获取数据
   */
  @Watch('selectNode', { immediate: true, deep: true })
  onSelectNodeChange(newValue: any, oldValue: any): void {
    if (!newValue) {
      GraphViewStore.setTableData({
        head: [],
        data: [], // 清空
      })
      return
    }
    if (isEqual(newValue, oldValue)) {
      return
    }
    // oldValue = oldValue || {}
    const { output: newOutput = [] } = newValue.data || {}
    // const {output: oldOutput = []} = oldValue.data || {}
    // const oldTableName = oldOutput[0] ? oldOutput[0].tableName : ''
    const newTableName = newOutput[0] ? newOutput[0].tableName : ''
    if (newTableName) {
      GraphViewStore.setTableData({
        head: [],
        data: [], // 清空
      })
      GraphViewStore.setCurrentHistory(null) // 清空当前历史记录
      GraphViewStore.setColumnFilters([]) // 清空筛选项
      this.painationParams = {
        ...this.painationParams,
        curPage: 1,
        filter: [],
      }
      this.getTableDataByNode('refresh')
    }
  }

  /**
   * 表格明细数据变化时，更新表格
   */
  // @Watch('tableData', { immediate: true, deep: true})
  // onTableDataChange(newValue: any) {
  //   if (newValue.length > 0) {
  //     (this.$refs.uTable as any).reloadData(newValue)
  //   }
  // }

  /**
   * column 分布项highlight时筛选表格明细数据
   */
  @Watch('columnFilters', { immediate: true, deep: true })
  async onColumnFiltersChange(newValue: any) {
    this.painationParams = {
      ...this.painationParams,
      curPage: 1,
      filter: newValue,
    }
    if (this.selectNode && this.selectNode.data) {
      // 有选中的node节点
      const response = await apiGetTableData({
        data: {
          ...this.painationParams,
          table: this.currentHistory
            ? this.currentHistory.data.table
            : (this.selectNode.data.output[0] || {}).tableName,
          taskId: this.selectNode.id,
        },
      })
      const { result } = response.data
      GraphViewStore.setTableData({
        head: this.tableColumns,
        data: result.data, // 添加到表格数据的末尾
        mode: 'detail', // detail:只是table detail更新，all: header和detail都更新
      })

      this.checkHeight()
      // 这里要确保数据表能够拿到
      const uTable = this.$refs.uTable as any
      if (uTable) {
        uTable.pagingScrollTopLeft(0, 0) // 表格滚动到顶部
      }
    }
  }

  boxHeight: number = 0

  public checkHeight(): void {
    const box = this.$el as HTMLElement
    this.boxHeight = box ? box.offsetHeight : 100
  }

  /**
   * 获取当前节点的具体信息：列字段、表明细等
   * refresh: 刷新表格数据
   * combine: 翻页追加
   */
  async getTableDataByNode(flag: 'refresh' | 'combine' = 'combine') {
    const response = await apiGetTableData({
      data: {
        ...this.painationParams,
        table:
          flag === 'combine' && this.currentHistory
            ? this.currentHistory.data.table
            : (this.selectNode.data.output[0] || {}).tableName, // 查询数据的表名取决于当前历史记录的表名
        taskId: this.selectNode.id,
      },
    })
    this.isLoading = false
    const result = response.data.result || {}
    this.totalPages = result.page ? result.page.totalPages : 0

    GraphViewStore.setTableDataCount(
      result.page ? result.page.totalElements : 0
    )
    GraphViewStore.setTableData({
      head: result.head || [],
      data:
        flag === 'combine'
          ? this.tableData.concat(result.data || [])
          : result.data || [], // 添加到表格数据的末尾或者刷新数据
      mode: flag === 'combine' ? 'detail' : 'all',
    })
  }

  /**
   * 表格内容滚动
   */
  onTableScroll(data: any) {
    const { scrollToBottom } = data // 是否滚动到底部
    if (
      scrollToBottom &&
      this.painationParams.curPage < this.totalPages &&
      !this.isLoading
    ) {
      this.isLoading = true
      this.painationParams = {
        ...this.painationParams,
        curPage: this.painationParams.curPage + 1,
      }
      this.getTableDataByNode()
    }
  }

  checkIsSelect(column: IColumn): boolean {
    return (
      this.selectColumns.findIndex((columnItem) => {
        return columnItem.name === column.name
      }) > -1
    )
  }

  getColumnInfo(name: string) {
    return GraphViewStore.tableColumns.find((item) => item.name === name)
  }

  // 查询某列中字段值为空的行
  private syncColumnNullCells(
    pageSize: number,
    columnName: string,
    callback: Function
  ) {
    const queryData: any = {
      curPage: 1,
      name: '_record_id_',
      pageSize,
      filter: [
        [
          {
            col: columnName,
            values: ['#NULL'],
            filterType: '=',
          },
        ],
      ],
      table: this.currentHistory
        ? this.currentHistory.data.table
        : (this.selectNode.data.output[0] || {}).tableName,
      taskId: this.selectNode.id,
    }

    const column = this.getColumnInfo(columnName)
    if (column && column.desc && ['varchar', 'text'].includes(column.desc)) {
      ;(queryData.filter[0] as Array<any>).push({
        col: columnName,
        values: [''],
        filterType: '=',
      })
    }

    tcolumnQueryDetail({
      data: queryData,
    }).then((response) => {
      if (response.data.code === 100) {
        if (callback) {
          callback(response)
        }
      }
    })
  }
  private syncNullRows(callback: Function) {
    const dataParameters: any = {
      curPage: 1,
      name: '_record_id_',
      pageSize: 1,
      filter: [],
      table: this.currentHistory
        ? this.currentHistory.data.table
        : (this.selectNode.data.output[0] || {}).tableName,
      taskId: this.selectNode.id,
      data: {
        transformType: 'SELECT_NULL',
      },
    }

    tcolumnQueryDetail({
      data: dataParameters,
    }).then((response) => {
      if (response.data.code === 100) {
        callback(response.data.result.data)
      } else {
        callback([])
      }
    })
  }

  /**
   * 检测列中是否含有空值, 传入到可视化推荐，方便
   */
  checkHasNull() {
    if (GraphViewStore.tableSelectionType === SelectionType.columns) {
      if (GraphViewStore.tableSelectColumns.length > 0) {
        this.syncColumnNullCells(
          1,
          GraphViewStore.tableSelectColumns[0].name,
          (response: any) => {
            if (response.data.result.data.length > 0) {
              GraphViewStore.setColumnHasNullCell(true)
            } else {
              GraphViewStore.setColumnHasNullCell(false)
            }
          }
        )
      } else {
        console.error('checkHasNull error: has no columns')
      }
    } else if (GraphViewStore.tableSelectionType === SelectionType.cells) {
      const cell = GraphViewStore.tableSelectCells[0]
      this.syncColumnNullCells(1, cell.columnName, (response: any) => {
        if (response.data.result.data.length > 0) {
          GraphViewStore.setColumnHasNullCell(true)
        } else {
          GraphViewStore.setColumnHasNullCell(false)
        }
      })
    } // todo check column
  }

  /**
   * 表头点击事件
   */
  onTableHeaderClick(columnData: any, event: any) {
    if (this.timeMouseUp - this.timeMouseDown > 300) {
      return
    }
    GraphViewStore.resetVrSettingValues()
    GraphViewStore.clearDataPreviewImmediately()
    const columnClicked = this.tableColumns.find((column) => {
      return column.name === columnData.property
    })
    if (columnClicked) {
      this.toggleSelectionChange(this.multipleSelection)
      GraphViewStore.setTableSelectRowNumbers([])
      this.clearTableSelectCells()
      if (this.isCtrlSelect(event)) {
        GraphViewStore.toggleSelectedColumn(columnClicked)
        GraphViewStore.toggleTableSelectColumn(columnClicked)
        // 这里可能导致没有任何列被选中
        if (GraphViewStore.tableSelectColumns.length === 0) {
          GraphViewStore.setTableSelectiontype(SelectionType.none)
        }
      } else {
        GraphViewStore.setSelectedColumns([columnClicked])
        GraphViewStore.setTableSelectColumns([columnClicked])
        this.closeGraphModal = false
      }

      if (GraphViewStore.tableSelectColumns.length > 0) {
        GraphViewStore.setTableSelectiontype(SelectionType.columns)
      } else {
        GraphViewStore.setTableSelectiontype(SelectionType.none)
      }

      if (GraphViewStore.tableSelectColumns.length === 1) {
        this.checkHasNull()
      }
    }
  }

  handleSelectionChange(value: Array<any>) {
    this.multipleSelection = value
    this.closeGraphModal = false
  }
  /**
   * 单元格点击事件
   */
  onCellClick(row: any, column: any, cell: HTMLElement, event: any) {
    GraphViewStore.resetVrSettingValues()
    GraphViewStore.clearDataPreviewImmediately()
    if (column.property === '$$$序号$$$') {
      GraphViewStore.setTableSelectColumns([])
      GraphViewStore.setSelectedColumns([])
      const dom = cell.querySelector('.data-cell')
      if (dom) {
        const index = dom.getAttribute('index') as string
        if (this.isCtrlSelect(event)) {
          GraphViewStore.toggleTableSelectData(row)
          GraphViewStore.toggleTableSelectRowNumber(Number.parseInt(index, 10))
          // 这里可能导致没有任何行被选中
          if (GraphViewStore.tableSelectRowDatas.length === 0) {
            GraphViewStore.setTableSelectiontype(SelectionType.none)
          }
        } else {
          GraphViewStore.setTableSelectRowNumbers([Number.parseInt(index, 10)])
          GraphViewStore.setTableSelectRowDatas([row])
        }
        if (GraphViewStore.tableSelectRowDatas.length > 0) {
          GraphViewStore.setTableSelectiontype(SelectionType.rows)
        }
        this.$nextTick(() => {
          if (GraphViewStore.tableSelectRowDatas.length > 0) {
            this.syncNullRows((dataRows: Array<any>) => {
              GraphViewStore.setTableHasNullRows(dataRows.length > 0)
            })
          }
        })
      }
    } else {
      const selection = (window as any).getSelection()
      if (
        ['varchar', 'text'].includes(column.desc) &&
        selection.baseNode &&
        selection.focusOffset &&
        selection.baseOffset >= 0 &&
        Math.abs(selection.focusOffset - selection.baseOffset) > 0
      ) {
        // 有刷选就直接屏蔽
        return
      }
      const dom = cell.querySelector('.data-cell')
      if (dom) {
        const index = dom.getAttribute('index') as string
        this.clearTableSlection()
        this.clearTableColumns()
        const cellData: CellInfo = {
          rowIndex: Number.parseInt(index, 10),
          columnName: column.property,
          _record_id_: row._record_id_ || '',
          cellValue: row[column.property],
        }

        // GraphViewStore.setTableSelectCells([cellData])
        // 多选
        if (event.ctrlKey) {
          GraphViewStore.toggleTableSelectCell(cellData)
        } else {
          GraphViewStore.setTableSelectCells([cellData])
          this.closeGraphModal = false
        }

        if (GraphViewStore.tableSelectCells.length > 0) {
          GraphViewStore.setTableSelectiontype(SelectionType.cells)
        } else {
          GraphViewStore.setTableSelectiontype(SelectionType.none)
        }
        this.$nextTick(() => {
          this.checkHasNull()
        })
      }
    }
  }
  checkIsSelectCell(scope: any) {
    return GraphViewStore.tableSelectCells.find((cellInfo: CellInfo) => {
      return (
        cellInfo.rowIndex === scope.$index &&
        cellInfo.columnName === scope.column.property
      )
    })
  }

  onCellTextMouseup(event: any, scope: any, column: IColumn) {
    if (column.desc && !['varchar', 'text'].includes(column.desc)) {
      this.clearSelections()
      return
    }
    setTimeout(() => {
      if (event.target && event.target instanceof HTMLElement) {
        const selection = (window as any).getSelection()
        if (
          selection.baseNode &&
          selection.focusOffset >= 0 &&
          selection.baseOffset >= 0 &&
          selection.focusOffset - selection.baseOffset !== 0
        ) {
          // 这里有可能从左向右或者从右到左刷选
          const selectData = (selection.baseNode.data as string).slice(
            Math.min(selection.baseOffset, selection.focusOffset),
            Math.max(selection.baseOffset, selection.focusOffset)
          )
          if (selectData) {
            // 这里要确保从左到右刷选|从右到左刷选后startIndex 都比 endIndex小
            const startIndex = Math.min(
              selection.baseOffset,
              selection.focusOffset
            )
            const endIndex = Math.max(
              selection.baseOffset,
              selection.focusOffset
            )
            let startWithWord = ''
            // todo selectData.indexOf(' ') === -1 这个条件待考虑
            /* eslint-disable */
            if (
              startIndex > 1 &&
              selectData.indexOf(' ') === -1 &&
              selection.baseNode.data[startIndex - 1] === ' '
            ) {
              const prefixArray: Array<string> = `${selection.baseNode.data}`
                .slice(0, startIndex - 1)
                .split(' ')
              // 这里有个特殊情况：  在 'aa  bbcc'字符串中，刷选bb后split出来最后 startWithWord 还是空字符串，这种情况暂时排除在 startWithWord之外
              startWithWord = prefixArray[prefixArray.length - 1]
            }
            let endWithword = ''
            if (
              endIndex < selection.baseNode.data.length - 2 &&
              selection.baseNode.data[endIndex] === ' '
            ) {
              // 这里特殊情况同上
              const subArray: Array<string> = `${selection.baseNode.data}`
                .slice(endIndex + 1, (selection.baseNode.data as string).length)
                .split(' ')
              endWithword = subArray[0] as string
            }
            let wordPos = 0
            // 选中字符作为单词（(前面有空格， 或者在首部)并且（后面有空格或刷选到末尾））
            if (
              (selection.baseNode.data[startIndex - 1] === ' ' ||
                startIndex === 0) &&
              (selection.baseNode.data[endIndex] === ' ' ||
                (selection.baseNode.data as string).length === endIndex)
            ) {
              if (startIndex === 0) {
                wordPos = 1
              } else {
                const prefixArray: Array<string> = `${selection.baseNode.data}`
                  .slice(0, startIndex - 1)
                  .split(' ')
                wordPos = prefixArray.length + 1
              }
            }
            // 刷选信息
            const selectionInfo: SelectionInfo = {
              startIndex, // 起始位
              endIndex, // 结束位置
              isStartWith: startIndex === 0, // 是否符合以XXX开头的条件
              isEndWidth: endIndex === selection.baseNode.data.length - 1, // 是否符合以XXX结尾的条件
              // 是否符合单词位置推荐的条件（前后有空格），这里位置指的是单词位置 todo 这里还要判断是英文？不好界定。待后续补充
              isWordPos:
                /* eslint-disable */
                selectData.indexOf(' ') === -1 && // 本身不能包含空格
                ((startIndex === 0 &&
                  selection.baseNode.data[endIndex] === ' ') || // 在最前面
                (selection.baseNode.data[startIndex - 1] === ' ' &&
                  selection.baseNode.data[endIndex] === ' ') || // 单词在中间
                  (selection.baseNode.data[startIndex - 1] === ' ' &&
                    endIndex === selection.baseNode.data.length - 1)), // 单词在末尾
              wordPos, // 单词位置
              isSelectionPos: true, // 是否符合选中位置一样的规则,这里位置指的是索引位置
              isSameSelection: true,
              isStartWithWord: startWithWord.length > 0, // 是否符合刷选内容前面为xx单词的规则，刷选内容在最前面且后面有空格
              startWithWord, // 前置单词
              isEndWithWord: endWithword.length > 0, // 是否符合刷选内容后面为xx单词的规则，刷选内容在最后面且前面有空格
              endWithword, // 后置单词
              _record_id_: scope.row._record_id_,
              rowIndex: scope.$index,
              columnName: column.name,
              selection: selectData,
            }

            // 以下是处理刷选多个单元格的问题
            const selectionInfoOld = GraphViewStore.tableSelectionInfo
              ? { ...GraphViewStore.tableSelectionInfo }
              : null
            // 确保新刷选的单元格在同一列
            if (
              this.isCtrlSelect(event) &&
              selectionInfoOld &&
              selectionInfoOld.columnName === selectionInfo.columnName
            ) {
              let mutipleSelectionInfo = selectionInfoOld.mutipleSelectionInfo
              if (!mutipleSelectionInfo) {
                // 如果没有多选选择信息
                mutipleSelectionInfo = {
                  // 这里包含一个隐式信息刷选的有肯能就是已刷选的那个单元格
                  [`${selectionInfoOld._record_id_}_${selectionInfoOld.rowIndex}`]: selectionInfoOld,
                  [`${selectionInfo._record_id_}_${selectionInfo.rowIndex}`]: selectionInfo,
                }
              } else {
                mutipleSelectionInfo[
                  `${selectionInfo._record_id_}_${selectionInfo.rowIndex}`
                ] = selectionInfo
              }
              const selectionInfoArray = Object.values(mutipleSelectionInfo) // 选中信息
              const isMutiple = selectionInfoArray.length > 1
              if (!isMutiple) {
                this.clearTableSelectCells()
                this.clearTableColumns()
                this.clearTableSlection()
                GraphViewStore.setTableSelectionInfo(selectionInfo)
                GraphViewStore.setTableSelectiontype(SelectionType.selection)
                this.$nextTick(() => {
                  this.clearWindowSelection()
                })
              } else {
                const selectionInfoSet = {
                  isMutiple: true, // 多选模式
                  startIndex: selectionInfo.startIndex,
                  endIndex: selectionInfo.endIndex,
                  isStartWith: selectionInfoArray.every(
                    (selection) =>
                      selection.isStartWith &&
                      selection.selection === selectData
                  ), // 所有选中都是以xxx开头
                  isEndWidth: selectionInfoArray.every(
                    (selection) =>
                      selection.isEndWidth && selection.selection === selectData
                  ), // 所有选中都是以xxx结尾
                  isWordPos: selectionInfoArray.every(
                    (selection) =>
                      selection.isWordPos && selection.wordPos === wordPos
                  ), // 单词位置模式？
                  wordPos, // 单词位置
                  isSelectionPos: selectionInfoArray.every(
                    (selection) =>
                      selection.startIndex === startIndex &&
                      selection.startIndex === endIndex
                  ), // 选中索引一致？
                  isStartWithWord: selectionInfoArray.every(
                    (selection) =>
                      selection.isStartWithWord &&
                      selection.startWithWord === startWithWord
                  ), // 都以xxx单词前置
                  startWithWord, // 前置单词
                  isEndWithWord: selectionInfoArray.every(
                    (selection) =>
                      selection.isEndWithWord &&
                      selection.endWithword === endWithword
                  ), // 都以xxx单词后置
                  endWithword, // 后置单词
                  _record_id_: scope.row._record_id_,
                  rowIndex: scope.$index,
                  columnName: column.name,
                  selection: selectData,
                  isSameSelection: selectionInfoArray.every(
                    (selection) => selection.selection === selectData
                  ), // 所有选中一致？
                  isSamePos: selectionInfoArray.every(
                    (selection) =>
                      selection.startIndex === startIndex &&
                      selection.endIndex === endIndex
                  ), // 所有选中位置一致？
                  rowIndexArray: selectionInfoArray.reduce((rec, item) => {
                    // 选中行索引集合
                    rec.push(item.rowIndex)
                    return rec
                  }, [] as Array<number>),
                  _record_id_Array: selectionInfoArray.reduce((rec, item) => {
                    // 选中行记录号集合
                    rec.push(item._record_id_)
                    return rec
                  }, [] as Array<string>),
                  mutipleSelectionInfo,
                }
                this.clearTableSelectCells()
                this.clearTableColumns()
                this.clearTableSlection()
                GraphViewStore.setTableSelectionInfo(selectionInfoSet)
                GraphViewStore.setTableSelectiontype(SelectionType.selection)
                this.$nextTick(() => {
                  this.clearWindowSelection()
                })
              }
            } else {
              this.clearTableSelectCells()
              this.clearTableColumns()
              this.clearTableSlection()
              GraphViewStore.setTableSelectionInfo(selectionInfo)
              GraphViewStore.setTableSelectiontype(SelectionType.selection)
              this.$nextTick(() => {
                this.clearWindowSelection()
              })
            }
            this.closeGraphModal = false
          } else {
            GraphViewStore.setTableSelectionInfo(null)
            if (GraphViewStore.tableSelectionType === SelectionType.selection) {
              GraphViewStore.setTableSelectiontype(SelectionType.none)
            }
          }
        }
      }
    }, 10)
  }
  /**
   * 设置数据选中状态
   */
  toggleSelectionChange(rows: Array<any>, isSelect: Boolean = false) {
    if (this.tableColumns && this.tableColumns.length > 0) {
      //  确保表格存在数据时执行
      if (rows) {
        rows.forEach((row) => {
          if (isSelect) {
            ;(this.$refs.uTable as any).toggleRowSelection([
              {
                row,
                selected: true,
              },
            ])
          } else {
            ;(this.$refs.uTable as any).toggleRowSelection([
              {
                row,
              },
            ])
          }
        })
      } else {
        ;(this.$refs.uTable as any).clearSelection()
      }
    }
  }
}
</script>

<style lang="less" scoped>
.comp-data-table {
  background: #fafafc;
  padding-left: 20px;

  /deep/ .plTableBox .el-table--mini td,
  /deep/ .plTableBox .el-table td {
    padding: 0;
  }

  /deep/ .plTableBox tr {
    th .cell {
      white-space: nowrap;
    }

    .cell {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
  }

  /deep/ .plTableBox td {
    .cell {
      padding-left: 0 !important;
      padding-right: 0 !important;

      .data-index {
        padding-left: 8px;
      }

      .data-cell .cell-content {
        padding-left: 8px;
        padding-right: 8px;
      }
    }
  }

  /deep/ .plTableBox .el-table td {
    background: transparent;
  }

  /deep/ .plTableBox .el-table tr {
    background: #fafafc;

    &:nth-child(2n) {
      background: #f3f3f3;
    }
  }

  /deep/ .plTableBox .has-gutter {
    .is-select-column {
      background: rgb(238, 239, 252) !important;
    }

    th .cell {
      color: #5d637e;
      font-family: 'Microsoft YaHei', '微软雅黑', 'Arial Narrow', Arial,
        sans-serif;
      font-size: 12px;
    }
  }

  /deep/ .is-select-column {
    background: rgb(238, 239, 252) !important;
  }

  /deep/ .select-tr {
    background: rgb(238, 239, 252) !important;
  }

  /deep/ .current-row {
    background: transparent;

    td:not(.is-select-column) {
      background: transparent !important;
    }

    .is-select-column {
      background: rgb(238, 239, 252) !important;
    }
  }

  /deep/ .select-tr.current-row {
    background: rgb(238, 239, 252) !important;

    td {
      background: transparent !important;
    }
  }

  /deep/ .is-select-cell {
    background: rgb(238, 239, 252) !important;
  }

  /deep/ .data-cell {
    display: block;
    height: 100%;
    padding: 6px 10px;
    position: relative;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 100%;

    .cell-content {
      display: block;
      height: auto;
      overflow: hidden;
      pointer-events: none;
      position: relative;
      text-overflow: ellipsis;

      &.null {
        color: transparent;
      }
    }

    .cell-hilight {
      bottom: 0;
      left: 0;
      overflow: hidden;
      padding: 6px 10px;
      position: absolute;
      right: 0;
      text-overflow: ellipsis;
      top: 0;
      user-select: text;
      white-space: nowrap;
      z-index: 0;
    }

    &::before,
    &::after {
      background: inherit;
      content: ' ';
      height: 100%;
      left: -10px;
      position: absolute;
      top: 0;
      width: 10px;
    }

    &::after {
      left: auto;
      right: -10px;
    }
  }

  /deep/ .seletion-cell {
    left: 0;
    overflow: hidden;
    pointer-events: none;
    position: absolute;
    text-overflow: ellipsis;
    top: 0;
    user-select: none;
    width: 100%;
    z-index: 1;
  }

  /deep/ .select-word {
    position: relative;

    &::after {
      background: rgba(103, 113, 252, 0.2);
      content: ' ';
      height: 32px;
      left: 0;
      pointer-events: none;
      position: absolute;
      top: -10px;
      width: 100%;
      z-index: 1;
    }
  }

  /deep/ .is-set-select-row,
  /deep/ .is-set-select-cell {
    background: rgb(238, 239, 252);
  }

  /deep/ .is-select-column {
    .is-set-select-cell {
      background: rgba(103, 113, 252, 0.1);
    }
  }
}
</style>
